#include "GCoordFrame3.h"
#include "GTransform3.h"

namespace GMath
{
	const GCoordFrame3	GCoordFrame3::Identitiy = GCoordFrame3(GVector3::One, GQuaternion::Identitiy, GVector3::Zero);

	GCoordFrame3::GCoordFrame3()
	{
		Scale = GVector3::One;
		Rotation = GQuaternion::Identitiy;
		Position = GVector3::Zero;

		Transformation = GMatrix4x4::Identity;

		Right = GVector3::UnitX;
		Up = GVector3::UnitY;
		Front = GVector3::UnitZ;

		Flags.LowerAll();
	}

	GCoordFrame3::GCoordFrame3(const GCoordFrame3& Frame)
	{
		*this = Frame;
		/*
		Scale = Frame.Scale;
		Position = Frame.Position;
		Rotation = Frame.Rotation;
		Transformation = Frame.Transformation;
		Right = Frame.Right;
		Up = Frame.Up;
		Front = Frame.Front;
		Flags = Frame.Flags;
		*/
	}

	GCoordFrame3::GCoordFrame3(const GVector3& Scale, const GQuaternion& Rotation, const GVector3& Position)
	{
		SetScale(Scale);
		SetRotation(Rotation);
		SetPosition(Position);
	}

	GCoordFrame3::~GCoordFrame3()
	{
	}

	GFrame3DirtyFlags GCoordFrame3::GetFlags() const
	{
		return Flags;
	}

	void GCoordFrame3::SetScale(const GVector3& NewScale)
	{
		Scale = NewScale;

		Flags.RaiseBits(G_F3DF_DIRTY_TRANSFORM);

		OnTransformChange();
	}

	const GVector3& GCoordFrame3::GetScale() const
	{
		return Scale;
	}

	void GCoordFrame3::SetPosition(const GVector3& NewPosition)
	{
		Position = NewPosition;

		Flags.RaiseBits(G_F3DF_DIRTY_TRANSFORM);

		OnTransformChange();
	}

	const GVector3& GCoordFrame3::GetPosition() const
	{
		return Position;
	}

	void GCoordFrame3::SetRotation(const GQuaternion& NewRotation)
	{
		Rotation = NewRotation;

		Flags.RaiseBits(G_F3DF_DIRTY_AXIS);
		Flags.RaiseBits(G_F3DF_DIRTY_TRANSFORM);

		OnTransformChange();
	}

	const GQuaternion& GCoordFrame3::GetRotation() const
	{
		return Rotation;
	}

	void GCoordFrame3::SetTransformation(const GMatrix4x4& Matrix)
	{
		GMatrix4x4::Decompose(Scale, Rotation, Position, Matrix);
		Flags.RaiseBits(G_F3DF_DIRTY_AXIS | G_F3DF_DIRTY_TRANSFORM);

		OnTransformChange();
	}

	const GMatrix4x4& GCoordFrame3::GetTransformation() const
	{
		if (Flags.Contains(G_F3DF_DIRTY_TRANSFORM))
		{
			GTransform3::CreateLocal(Transformation, GetScale(), GetRotation(), GetPosition());
			Flags.LowerBits(G_F3DF_DIRTY_TRANSFORM);
		}

		return Transformation;
	}

	const GVector3& GCoordFrame3::GetRight() const
	{
		if (Flags.Contains(G_F3DF_DIRTY_RIGHT))
		{
			GQuaternion::Multiply(Right, GVector3::UnitX, Rotation);
			Flags.LowerBits(G_F3DF_DIRTY_RIGHT);
		}

		return Right;
	}

	const GVector3& GCoordFrame3::GetUp() const
	{
		if (Flags.Contains(G_F3DF_DIRTY_UP))
		{
			GQuaternion::Multiply(Up, GVector3::UnitY, Rotation);
			Flags.LowerBits(G_F3DF_DIRTY_UP);
		}

		return Up;
	}

	const GVector3& GCoordFrame3::GetFront() const
	{
		if (Flags.Contains(G_F3DF_DIRTY_FRONT))
		{
			GQuaternion::Multiply(Front, GVector3::UnitZ, Rotation);
			Flags.LowerBits(G_F3DF_DIRTY_FRONT);
		}

		return Front;
	}

	const GCoordFrame3& GCoordFrame3::operator = (const GCoordFrame3& Frame)
	{
		Scale = Frame.Scale;
		Rotation = Frame.Rotation;
		Position = Frame.Position;
		Transformation = Frame.Transformation;
		Right = Frame.Right;
		Up = Frame.Up;
		Front = Frame.Front;
		Flags = Frame.Flags;

		return *this;
	}

	void GCoordFrame3::OnTransformChange()
	{
	}

}